/*
 * ==========================================================================*\
 * | $Id$
 * |*-------------------------------------------------------------------------*|
 * | Copyright (C) 2009 Virginia Tech | | This file is part of CloudSpace. | |
 * CloudSpace is free software; you can redistribute it and/or modify | it under
 * the terms of the GNU General Public License as published | by the Free
 * Software Foundation; either version 3 of the License, or | (at your option)
 * any later version. | | CloudSpace is distributed in the hope that it will be
 * useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General
 * Public License for more details. | | You should have received a copy of the
 * GNU General Public License | along with CloudSpace; if not, see
 * <http://www.gnu.org/licenses/>.
 * \*==========================================================================
 */

package cloudspace.security.permissions;

import cloudspace.security.CloudSpaceUser;


// -------------------------------------------------------------------------
/**
 * Defines whether a resource can be read from or written to. Subclasses must
 * implement the {@link #matchesUser(CloudSpaceUser)} method to provide the
 * logic for determining whether the token applies to a particular user.
 * 
 * @author Tony Allevato
 * @author Last changed by $Author$
 * @version $Revision$, $Date$
 */
public abstract class PermissionToken
{
    // ~ Constructors ..........................................................

    // ----------------------------------------------------------
    protected PermissionToken( boolean allowsRead, boolean allowsWrite )
    {
        this.allowsRead = allowsRead;
        this.allowsWrite = allowsWrite;
    }


    // ----------------------------------------------------------
    protected PermissionToken( String permissions )
    {
        this( permissions.contains( "r" ), permissions.contains( "w" ) );
    }


    // ~ Methods ...............................................................

    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether this permission token applies to the
     * specified user. For example, a user-based permission would match if the
     * users are the same, a group-based permission would match if the user is a
     * member of the token's group, and the "anybody" token would match any
     * user.
     * 
     * @param user
     *            the user
     * @return true if the token applies to the user, otherwise false
     */
    public abstract boolean matchesUser( CloudSpaceUser user );


    // ----------------------------------------------------------
    /**
     * A weaker form of equality. Tests to see if the tokens are the same type,
     * and if so match the same entity (group or user), but not necessarily that
     * they have the same read/write permissions.
     * 
     * @param token
     *            the other token
     * @return true if the tokens are similar, otherwise false
     */
    public abstract boolean isSimilarTo( PermissionToken token );


    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether this token provides read access to its
     * associated entity.
     * 
     * @return true if the token provides read access, otherwise false
     */
    public boolean allowsRead()
    {
        return allowsRead;
    }


    // ----------------------------------------------------------
    public void setAllowsRead( boolean value )
    {
        allowsRead = value;
        PermissionsManager.getInstance().updateConfigFile();
    }


    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether the specified user can read the resource
     * associated with this permission token.
     * 
     * @param user
     *            the user
     * @return true if the user can read it, otherwise false
     */
    public boolean canUserRead( CloudSpaceUser user )
    {
        return allowsRead && matchesUser( user );
    }


    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether this token provides write access to its
     * associated entity.
     * 
     * @return true if the token provides write access, otherwise false
     */
    public boolean allowsWrite()
    {
        return allowsWrite;
    }


    // ----------------------------------------------------------
    public void setAllowsWrite( boolean value )
    {
        allowsWrite = value;
        PermissionsManager.getInstance().updateConfigFile();
    }


    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether the specified user can write to the
     * resource associated with this permission token.
     * 
     * @param user
     *            the user
     * @return true if the user can write to it, otherwise false
     */
    public boolean canUserWrite( CloudSpaceUser user )
    {
        return allowsWrite && matchesUser( user );
    }


    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether the specified user has any access to the
     * resource associated with this permission token. This method is currently
     * a shorthand way of expressing
     * <code>canUserRead(user) || canUserWrite(user)</code>.
     * 
     * @param user
     *            the user
     * @return true if the user has any access to the resource, otherwise false
     */
    public boolean canUserAccess( CloudSpaceUser user )
    {
        return canUserRead( user ) || canUserWrite( user );
    }


    // ----------------------------------------------------------
    /**
     * Gets the specificity of this type of permission token. In the event that
     * multiple tokens match a user, the token with the highest specificity is
     * used to determine the final permissions. For example, the "anybody" token
     * has the lowest specificity, followed by the group token, and then the
     * user token has the highest specificity.
     * 
     * @return an integer denoting the specificity of the token
     */
    public abstract int getSpecificity();

    // ~ Static/instance variables .............................................

    private boolean allowsRead;

    private boolean allowsWrite;
}
